/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    saradc.c
 *  @brief   saradc driver
 *  @version v1.0
 *  @date    12  Sep. 2023
 *  @author  liusg
 ****************************************************************/

#include "saradc.h"
#include "irq.h"
#include "error.h"

#define SARADC_CHECK_EXP(EXPR, ERROR_CODE)          CHECK_EXP(EXPR, ercd, ERROR_CODE, error_exit)

static saradc_int_callback saradc_intcb = NULL;

static void saradc_sample_time_cfg(uint32_t samp_time, uint32_t switch_time)
{
	SARADC->SAMP_CTRL &= (~SAMP_CTRL_SAMP_TIME_MASK) | (~SAMP_CTRL_SWITCH_TIME_MASK);
	SARADC->SAMP_CTRL = (samp_time << SAMP_CTRL_SAMP_TIME_POS) |
                        (switch_time << SAMP_CTRL_SWITCH_TIME_POS);
}

void saradc_bais_power_en(bool enable)
{
	if(enable == true) {
		SARADC->ADC_CTRL0 &= ~ADC_CTRL0_BAIS_DISABLE;
	} else {
		SARADC->ADC_CTRL0 |= ADC_CTRL0_BAIS_DISABLE;
	}
}

void saradc_analog_power_en(bool enable)
{
	if(enable == true) {
		SARADC->ADC_CTRL0 &= ~ADC_CTRL0_PD_DISABLE;
	} else {
		SARADC->ADC_CTRL0 |= ADC_CTRL0_PD_DISABLE;
	}
}

int32_t saradc_chans_enable(uint8_t chan_nums)
{
	int32_t ercd = E_OK;
	SARADC_CHECK_EXP(chan_nums <= SARADC_CHAN_MAX, E_PAR);

	SARADC->ADC_CTRL0 &= ADC_CTRL0_CHAN_EN_MASK;
	SARADC->ADC_CTRL0 |= (chan_nums >> ADC_CTRL0_CHAN_EN_POS);

error_exit:
	return ercd;

}

void saradc_en(bool enable)
{
	SARADC->ADC_CTRL2 = (enable ? ADC_CTRL2_ADC_ENBALE : 0);
}

int32_t saradc_chan_cali_cfg(saradc_chan chan, uint32_t b_para, uint32_t k_para)
{
	int32_t ercd = E_OK;
	SARADC_CHECK_EXP(chan < SARADC_CHAN_MAX, E_PAR);
	SARADC_CHECK_EXP(b_para < BIT(13), E_PAR);
	SARADC_CHECK_EXP(k_para < BIT(13), E_PAR);

	SARADC->CALI_CTRL[chan] = ADC_CHAN_CALI_B_EN_MASK | ADC_CHAN_CALI_B_EN_MASK |
        (b_para << ADC_CHAN_CALI_B_PARA_POS) | (k_para << ADC_CHAN_CALI_K_PARA_POS);

error_exit:
	return ercd;
}

void saradc_temp_threshold_cfg(uint32_t value)
{
	SARADC->TEMP_THRES_CTRL = value;
}

int32_t saradc_temp_chan_cfg(saradc_chan chan)
{
	int32_t ercd = E_OK;
	SARADC_CHECK_EXP(chan < SARADC_CHAN_MAX, E_PAR);

	SARADC->ADC_CTRL1 &= ADC_CTRL1_TEMP_CHAN_CFG_MASK;
	SARADC->ADC_CTRL1 |= (chan << ADC_CTRL1_TEMP_CHAN_CFG_POS);

error_exit:
	return ercd;
}

int32_t saradc_leak_chan_cfg(saradc_chan chan)
{
	int32_t ercd = E_OK;
	SARADC_CHECK_EXP(chan < SARADC_CHAN_MAX, E_PAR);

	SARADC->ADC_CTRL1 &= ADC_CTRL1_LEAK_CHAN_CFG_MASK;
	SARADC->ADC_CTRL1 |= (chan << ADC_CTRL1_LEAK_CHAN_CFG_POS);

error_exit:
	return ercd;
}

int32_t saradc_chan_map(saradc_map_chan map_chan, saradc_chan chan)
{
	uint32_t temp;
	int32_t ercd = E_OK;
	SARADC_CHECK_EXP(map_chan < MAP_CHAN_MAX, E_PAR);
	SARADC_CHECK_EXP(chan < SARADC_CHAN_MAX, E_PAR);

	temp = SARADC->CHAN_MAP_CTRL[map_chan >> 3];
	temp &= ~(0x0F << ((map_chan & 0x07) * 4));
	temp |= (chan << ((map_chan & 0x07) * 4));
	SARADC->CHAN_MAP_CTRL[map_chan >> 3] = temp;

error_exit:
	return ercd;
}

void saradc_leak_samp_rate_cfg(uint32_t samp_rate)
{
	SARADC->ADC_CTRL1 &= ADC_CTRL1_LEAK_SAMP_RATE_MASK;
	SARADC->ADC_CTRL1 |= (samp_rate << ADC_CTRL1_LEAK_SAMP_RATE_POS);
}

int32_t saradc_chan_samp_rate_cfg(saradc_chan chan, uint32_t sample_rate)
{
	int32_t ercd = E_OK;
	SARADC_CHECK_EXP(chan < SARADC_CHAN_MAX, E_PAR);

	SARADC->SAMP_RATE_CTRL[chan] = sample_rate;

error_exit:
	return ercd;
}

void saradc_en_int_callback(saradc_int_callback cb)
{
	saradc_intcb = cb;
	//enable int
	SARADC->INT_MASK = 1;
	irq_enable(INT_SARADC_IRQn);
}

void saradc_int_handler(void *arg)
{
	(void)arg;

	if (SARADC->INT_STA) {
		//claer the int
		SARADC->INT_CLR = 1;
		if(saradc_intcb) {
			saradc_intcb();
		}
	}
}

void saradc_default_init(void)
{
	uint32_t chan;
	saradc_sample_time_cfg(ADC_DEFAULT_SAMP_TIME, ADC_DEFAULT_SWITCH_TIME);
	saradc_bais_power_en(true);
	saradc_analog_power_en(true);
	saradc_chans_enable(ADC_DEFAULT_CHAN_NUMS);
	//chan map config
	//arc1:0, arc2:1, arc3:2, ext_chan0-7:3-10, leak:11, temp:12
	saradc_temp_chan_cfg(TEMP_CHAN);
	saradc_leak_chan_cfg(LEAK_CHAN);
	saradc_chan_map(ARC1_MAP_CHAN, ARC1_CHAN);
	saradc_chan_map(ARC2_MAP_CHAN, ARC2_CHAN);
	saradc_chan_map(ARC3_MAP_CHAN, ARC3_CHAN);
	saradc_chan_map(EXT0_MAP_CHAN, SARADC_CHAN3);
	saradc_chan_map(EXT1_MAP_CHAN, SARADC_CHAN4);
	saradc_chan_map(EXT2_MAP_CHAN, SARADC_CHAN5);
	saradc_chan_map(EXT3_MAP_CHAN, SARADC_CHAN6);
	saradc_chan_map(EXT4_MAP_CHAN, SARADC_CHAN7);
	saradc_chan_map(EXT5_MAP_CHAN, SARADC_CHAN8);
	saradc_chan_map(EXT6_MAP_CHAN, SARADC_CHAN9);
	saradc_chan_map(EXT7_MAP_CHAN, SARADC_CHAN10);
	//arc sample rate 204.8K
	saradc_chan_samp_rate_cfg(ARC1_CHAN, ADC_SAMP_RATE_204800);
	saradc_chan_samp_rate_cfg(ARC2_CHAN, ADC_SAMP_RATE_204800);
	saradc_chan_samp_rate_cfg(ARC3_CHAN, ADC_SAMP_RATE_204800);
	//config chan3-10 samp rate, must config but may unuse, samp rate >= leak samp rate
	//ext chan sample rate 6.4K
	for (chan = SARADC_CHAN3; chan < LEAK_CHAN; chan++) {
		saradc_chan_samp_rate_cfg(chan, ADC_SAMP_RATE_6400);
	}
	//leak sample rate 6.4K
	saradc_leak_samp_rate_cfg(ADC_SAMP_RATE_6400);
	//temp sample rate 3.2K
	saradc_chan_samp_rate_cfg(TEMP_CHAN, ADC_SAMP_RATE_3200);
	// saradc config enable, the saradc work enable bit in sdadc reg
	saradc_en(true);

	irq_attach(INT_SARADC_IRQn, saradc_int_handler, NULL);
	irq_disable(INT_SARADC_IRQn);

}

